/* Copyright (c) 2010, David Kreuter. See LICENSE for more information */

#include "headers.h"

const char *tex_format[] = { "", "A3I5", "4-Color", "16-Color", "256-Color", "4x4-Texel", "A5I3", "Direct Texture" };

rgba *make_mat(uint8 tex_id, uint8 pal_id, uint8 repeat, tex* t){
	// make_mat doesn't have START and END because its called per frame
	tex_tex *tt=t->tex+tex_id;
	tex_pal *tp=t->pal+pal_id;
	uint32 num_pixels=tt->w*tt->h;
	uint32 *pixel=malloc(num_pixels*4);
	rgba *prgba=(rgba*)pixel;

	uint8 *data=tt->data;
	uint32 *pal=(uint32*)tp->color;
	for(uint32 x=0;x<tt->w;x++){ // As a fallback
		for(uint32 y=0;y<tt->h;y++){
			prgba[x+y*(tt->w)].r=x*256/tt->w;
			prgba[x+y*(tt->w)].g=y*256/tt->h;
			prgba[x+y*(tt->w)].b=tex_id*64;
			prgba[x+y*(tt->w)].a=255;
		}
	}
	tp->color[0].a=0xFF*(1-tt->color0);
	switch(tt->format){
	case 0: ERROR("Texture-format 0?!\n");
		return 0;
	case 1: for(uint32 p=0;p<num_pixels;p++){
			pixel[p]=pal[data[p]&0x1f];
			prgba[p].a=  data[p]&0xe0;
		}break;
	case 2: for(uint32 p=0;p<num_pixels;p++)
			pixel[p]=pal[(tt->data[p/4]>>((p&3)<<1))&3];
		break;
	case 3: for(uint32 p=0;p<num_pixels;p++)
			pixel[p]=pal[(tt->data[p/2]>>((p&1)<<2))&15];
		break;
	case 4: for(uint32 p=0;p<num_pixels;p++)
			pixel[p]=pal[data[p]];
		break;
	case 6: for(uint32 p=0;p<num_pixels;p++){
			pixel[p]=pal[data[p]&0x07];
			prgba[p].a=  data[p]&0xf8;
		}break;
	default:
		DEBUG("TODO: Implement texture-format %d\n",tt->format);
		break;
	}
	//FLIPPING TIME
	uint32 *flipped_pixel=malloc(num_pixels*4*WRF(repeat)*HRF(repeat));
	if(repeat==0x07){
		for(uint32 y=0;y<tt->w;y++)
			for(uint32 x=0;x<tt->h;x++){
				flipped_pixel[ y   *tt->h*2+x  ]=
				flipped_pixel[(y+1)*tt->h*2-x-1]=
					pixel[x+y*tt->h];
			}
	}else if(repeat==0x0b){
		for(uint32 y=0;y<tt->w;y++)
			for(uint32 x=0;x<tt->h;x++){
				flipped_pixel[       y     *tt->h+x]=
				flipped_pixel[(tt->h*2-y-1)*tt->h+x]=
					pixel[x+y*tt->h];
			}
	}else if(repeat==0x0f){
	}else{
		free(flipped_pixel);
		return (rgba*)pixel;
	}
	free(pixel);
	return (rgba*)flipped_pixel;
}

tex *read_tex(uint8 *buf, uint32 len){
	START(read_tex);
	tex *t=(tex*)malloc(sizeof(tex));

	MAGIC(0,TEX0,read_tex);
	CHECK_LEN(4,read_tex);
	t->len=len; // See .h

	uint32 texdata_len   =RS(12)<<3;
	uint32     tex_offset=60;
	uint32 texdata_offset=RL(20);

	uint32   sptex_len   =RS(28)<<3;
	uint32   sptex_offset=RL(36);
	uint32  spdata_offset=RL(40);

	uint32 paldata_len   =RS(48)<<3;
	uint32     pal_offset=RL(52);
	uint32 paldata_offset=RL(56);

	t->num_texs=buf[tex_offset+1];
	t->num_pals=buf[pal_offset+1];
	t->tex=calloc(t->num_texs,sizeof(tex_tex));
	t->pal=calloc(t->num_pals,sizeof(tex_pal));
	t->pal_start=paldata_offset;

	DEBUG("Texdata Offset: %8x Len: %8x\n",texdata_offset,texdata_len);
	DEBUG("Sptex   Offset: %8x Len: %8x\n",  sptex_offset,  sptex_len);
	DEBUG("Paldata Offset: %8x Len: %8x\n",paldata_offset,paldata_len);
	DEBUG("Offset of Pal.: %8x Spx: %8x\n",    pal_offset,  sptex_offset);
	DEBUG("Nr. of Tex.: %d Num. of Pal.: %d\n",t->num_texs,t->num_pals);

	int i;
	for(i=0;i<t->num_texs;i++){
		tex_tex *T=t->tex+i;
		READ_NAME(T->name,buf+tex_offset+16+t->num_texs*12+i*16);
		static const uint8 bpp[8]={0,8,2,4,8,2,8,16};
		uint16 offset=RS(tex_offset+16+t->num_texs*4+i*8+0)<<3;
		uint16 param =RS(tex_offset+16+t->num_texs*4+i*8+2);
		T->w     =8<<((param>> 4)&7);
		T->h     =8<<((param>> 7)&7);
		T->format=   ((param>>10)&7);
		T->color0=   ((param>>13)&1);
		T->offset=offset+texdata_offset;
		T->len   =T->w*T->h*bpp[T->format]/8;
		T->data  =malloc(T->len);
		memcpy(T->data,buf+T->offset,T->len);
		DEBUG("%d. tex_tex offset: %8x '%s' %s %dx%d  Transp. %d\n",
			i,T->offset,T->name,tex_format[T->format],T->w,T->h,T->color0);
	}

	for(uint32 i=0;i<t->num_pals;i++){
		INIT_OFF_AND_NAME(tex,t,pal,paldata,p);
		p->offset-=paldata_offset;
		p->offset<<=3;
		p->offset&=0xFFFF;
		p->offset+=paldata_offset;
		p->num_colors=(len-p->offset)/2;
	}
	for(uint32 i=0;i<t->num_pals;i++){
		for(uint32 j=0;j<t->num_pals;j++){
			uint16 nn_colors=t->pal[j].offset-t->pal[i].offset;
			if(nn_colors>0&&nn_colors<t->pal[i].num_colors&&i!=j){
				t->pal[i].num_colors=nn_colors/2;
			}
		}
	}
	for(uint32 i=0;i<t->num_pals;i++){
		tex_pal *p=t->pal+i;
		DEBUG("Filling '%s' with %d colors\n",t->pal[i].name,t->pal[i].num_colors);
		p->color=malloc(p->num_colors*sizeof(rgba));
		for(uint8 j=0;j<p->num_colors;j++){
			uint16 col=RS(p->offset+j*2);
			p->color[j].r=((col>> 0)&0x1f)<<3;
			p->color[j].g=((col>> 5)&0x1f)<<3;
			p->color[j].b=((col>>10)&0x1f)<<3;
			p->color[j].a=0xFF;
		}
	}

	END(read_tex,t);
}

int write_tex(tex *t, uint8 *buf, uint32 len){
	START(write_tex);

	RL(0)=TEX0;
	RL(4)=len;
	RL(8)=0;

	uint32 texdata_len   =0;
	uint32     tex_offset=60;
	uint32 texdata_offset=92+t->num_texs*52; //Wrong for num_texs!=num_pals

	uint32   sptex_len   =0;
	uint32   sptex_offset=texdata_len+texdata_offset;
	uint32  spdata_offset=sptex_offset;

	uint32 paldata_len   =len-t->pal_start;
	uint32     pal_offset=76+28*t->num_texs;
	uint32 paldata_offset=t->pal_start;

	for(uint32 i=0;i<t->num_texs;i++){
		tex_tex *T=t->tex+i;
		memcpy(buf+tex_offset+16+t->num_texs*12+i*16,T->name,16);
		T->offset=texdata_len>>3;
		RS(tex_offset+16+t->num_texs*4+i*8+0)=T->offset;
		RS(tex_offset+16+t->num_texs*4+i*8+2)=
			(T->color0<<13)+(T->format<<10)+(T->h<<1)+(T->w<<4);
		texdata_len+=T->len;
	}
	for(uint32 i=0;i<t->num_texs;i++){
		tex_tex *T=t->tex+i;
		memcpy(buf+texdata_offset+T->offset,T->data,T->len);
	}

	for(uint32 i=0;i<t->num_pals;i++){
		tex_pal *p=t->pal+i;
		memcpy(buf+pal_offset+16+t->num_pals*8+i*16,p->name,16);
	}

	RS(12)=texdata_len>>3;
	// 2
	RL(16)=0;
	RL(20)=texdata_offset;
	RL(24)=0;
	RS(28)=sptex_len>>3;
	// 6
	RL(36)=sptex_offset;
	RL(40)=spdata_offset;
	RL(44)=0;
	RS(48)=paldata_len>>3;
	// 2
	RL(52)=pal_offset;
	RL(56)=paldata_offset;
	// 4

	buf[tex_offset  ]=0;
	buf[tex_offset+1]=t->num_texs;
	buf[pal_offset  ]=0;
	buf[pal_offset+1]=t->num_pals;

	END(write_tex,1);
}

// Called through LOOP_FREE (no START, no END, no entry in header-file)
void free_tex_tex(tex_tex *t){free(t->data );}
void free_tex_pal(tex_pal *p){free(p->color);}

void free_tex(tex *t){
	START(free_tex);
	if(t){
		FREE_LOOP(t,tex,free_tex_tex);
		FREE_LOOP(t,pal,free_tex_pal);
		free(t);
	}
	ENDV(free_tex);
}

uint32 size_tex(tex *t){
	START(size_tex);
	END(size_tex,t->len); // See .h
}
